// Triangle.cpp
// Our first OpenGL program that will just draw a triangle on the screen.
#include "stdafx.h"
#include <GLTools.h>            // OpenGL toolkit

#ifdef __APPLE__
#include <glut/glut.h>          // OS X version of GLUT
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>            // Windows FreeGlut equivalent

#endif

#include <glFrame.h>
#include <glFrustum.h> 
#include <StopWatch.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

void SetUpFrame(GLFrame &frame,const M3DVector3f origin,
				const M3DVector3f forward,
				const M3DVector3f up);

void LookAt(GLFrame &frame, const M3DVector3f eye,
        const M3DVector3f at,
        const M3DVector3f up);

void drawPyramid1();
void drawPyramid2();

CStopWatch timer;

GLFrame frame;
GLFrame cameraFrame;
GLFrustum viewFrustum;

//M3DMatrix44f VPMatrix;
M3DMatrix44f mCamera;
M3DMatrix44f mFrame;

GLuint shader;
static GLint MVPMatrixLocation;

///////////////////////////////////////////////////////////////////////////////
// Window has changed size, or has just been created. In either case, we need
// to use the window dimensions to set the viewport and the projection matrix.

void ChangeSize(int w, int h) {
    glViewport(0, 0, w, h);
	viewFrustum.SetPerspective(40, w/h, 0 , 100);
}


///////////////////////////////////////////////////////////////////////////////
// This function does any needed initialization on the rendering context.
// This is the first opportunity to do any OpenGL related tasks.

void SetupRC()
{
    // Blue background
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

    shader = gltLoadShaderPairWithAttributes("pass_thru_shader.vp", "pass_thru_shader.fp",
            2, GLT_ATTRIBUTE_VERTEX, "vVertex", GLT_ATTRIBUTE_COLOR, "vColor");
    fprintf(stdout, "GLT_ATTRIBUTE_VERTEX : %d\nGLT_ATTRIBUTE_COLOR : %d \n",
            GLT_ATTRIBUTE_VERTEX, GLT_ATTRIBUTE_COLOR);

	MVPMatrixLocation=glGetUniformLocation(shader,"MVPMatrix");
		if(MVPMatrixLocation==-1)
		{
			fprintf(stderr,"uniform MVPMatrix could not be found\n");
		}
	M3DVector3f eye = {0.0f, 0.0f, 0.0f};
	M3DVector3f at = {0.0f, 5.0f, -1.0f};
	M3DVector3f up = {0.0f, 1.0f, 0.0f};
	LookAt(frame,eye,at,up);
}

void SetUpFrame(GLFrame &frame,const M3DVector3f origin,
				const M3DVector3f forward,
				const M3DVector3f up) {
	frame.SetOrigin(origin);
	frame.SetForwardVector(forward);
	M3DVector3f side,oUp;
	m3dCrossProduct3(side,forward,up);
	m3dCrossProduct3(oUp,side,forward);
	frame.SetUpVector(oUp);
	frame.Normalize();
}

void LookAt(GLFrame &frame, const M3DVector3f eye,
        const M3DVector3f at,
        const M3DVector3f up) {
    M3DVector3f forward;
    m3dSubtractVectors3(forward, at, eye);
    SetUpFrame(frame, eye, forward, up);
}

///////////////////////////////////////////////////////////////////////////////
// Called to draw scene

void RenderScene(void)
{
	int x,y;
    // Clear the window with current clearing color
	M3DMatrix44f cameraMatrix;
    M3DMatrix44f VPMatrix;
	//const float projectionMatrix[]
		/*= { 1, 0, 0, 0,
                          0, 1, 0, 0,
						  0, 0, 1, 2,
						  0, 0, 0, 1};*/

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    glUseProgram(shader);
	
	cameraFrame.GetCameraMatrix(cameraMatrix);
	

	//projectionMatrix=viewFrustum.GetProjectionMatrix();
	frame.GetMatrix(mFrame);

	m3dMatrixMultiply44(VPMatrix,mFrame,cameraMatrix);

	//frame.GetMatrix(mFrame);
	//m3dMatrixMultiply44(VPMatrix,mFrame,mCamera);

    glUniformMatrix4fv(MVPMatrixLocation,1,GL_FALSE,VPMatrix);

	for(x=-10;x<=10;x++)
		{
	glBegin(GL_LINES);
    glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 0.7, 0.7, 0.7);//grey
    glVertex3f(-10.0f, x*1.0f, 0.0f);
    glVertex3f(10.0f, x*1.0f, 0.0);
	glVertex3f(x*1.0f, -10.0f, 0.0f);
    glVertex3f(x*1.0f, 10.0f, 0.0);
	glEnd();
		}

	M3DMatrix44f mM;
	m3dTranslationMatrix44(mM,0.0f,0.0f,-1.0f);
	M3DMatrix44f mMVP;
	m3dMatrixMultiply44(mMVP,VPMatrix,mM);
	glUniformMatrix4fv(MVPMatrixLocation,1,GL_FALSE,mMVP);


	drawPyramid1();  
	drawPyramid2();
	
	//for (y=-10;y<=10;y++)
		
    // Perform the buffer swap to display back buffer
    glutSwapBuffers();

	cameraFrame.RotateLocalZ(0.015);

	//cameraFrame.GetCameraMatrix(mCamera);
	//viewFrustum.SetPerspective(kat widzenia,width/height,near,far);
	
	/*M3DVector3f at = {0.0f, 0.0f, 0.0f};
	M3DVector3f up = {0.0f, 0.0f, 1.0f};
	M3DVector3f eye;
	float angle = timer.GetElapsedSeconds()*3.14f; //co 3 sekundy
	eye[0]=6.8f*cos(angle);
	eye[1]=6.0f*sin(angle);
	eye[2]=5.0f; 
	LookAt(frame,eye,at,up);*/



glutPostRedisplay();
}


void drawPyramid1() {

		  glBegin(GL_QUADS);                      // Draw A Quad 
		    glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 0.3, 0.3, 0.3);
			glVertex3f(-0.5f, 0.5f, 0.0f);              // Top Left 
			glVertex3f( 0.5f, 0.5f, 0.0f);              // Top Right 
			glVertex3f( 0.5f,-0.5f, 0.0f);              // Bottom Right 
			glVertex3f(-0.5f,-0.5f, 0.0f);              // Bottom Left 
	   glEnd();

       glBegin(GL_TRIANGLES);                      // Draw A Triangle 
		    //dolny
			glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 0.0, 1.0, 0.0);
			glVertex3f(-0.5f, -0.5f, 0.0f);          
			glVertex3f(0.5f,-0.5f, 0.0f);   
			glVertex3f(0.0f,0.0f, 1.0f);         
			//gorny
			glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 1.0, 1.0, 0.0);
			glVertex3f(-0.5f, 0.5f, 0.0f);          
			glVertex3f(0.5f,0.5f, 0.0f);   
			glVertex3f(0.0f,0.0f, 1.0f);        
			//prawy
			glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 1.0, 0.0, 0.0);
			glVertex3f(0.5f, -0.5f, 0.0f);          
			glVertex3f(0.5f,0.5f, 0.0f);   
			glVertex3f(0.0f,0.0f, 1.0f); 
			//lewy
			glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 0.0, 0.0, 1.0);
			glVertex3f(-0.5f, -0.5f, 0.0f);          
			glVertex3f(-0.5f,0.5f, 0.0f);   
			glVertex3f(0.0f,0.0f, 1.0f); 
	   glEnd(); 

}


void drawPyramid2() {

		glBegin(GL_QUADS);                      // Draw A Quad 
		    glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 0.3, 0.3, 0.3);
			glVertex3f(-0.5f, 0.5f, 2.0f);              // Top Left 
			glVertex3f( 0.5f, 0.5f, 2.0f);              // Top Right 
			glVertex3f( 0.5f,-0.5f, 2.0f);              // Bottom Right 
			glVertex3f(-0.5f,-0.5f, 2.0f);              // Bottom Left 
	   glEnd();

       glBegin(GL_TRIANGLES);                      // Draw A Triangle 
		    //dolny
			glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 0.0, 0.0, 1.0);
			glVertex3f(-0.5f, -0.5f, 2.0f);          
			glVertex3f(0.5f,-0.5f, 2.0f);   
			glVertex3f(0.0f,0.0f, 1.0f);         
			//gorny
			glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 0.0, 1.0, 0.0);
			glVertex3f(-0.5f, 0.5f, 2.0f);          
			glVertex3f(0.5f,0.5f, 2.0f);   
			glVertex3f(0.0f,0.0f, 1.0f);        
			//prawy
			
			glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 1.0, 1.0, 0.0);
			glVertex3f(0.5f, -0.5f, 2.0f);          
			glVertex3f(0.5f,0.5f, 2.0f);   
			glVertex3f(0.0f,0.0f, 1.0f); 
			//lewy
			glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 1.0, 0.0, 0.0);
			glVertex3f(-0.5f, -0.5f, 2.0f);          
			glVertex3f(-0.5f,0.5f, 2.0f);   
			glVertex3f(0.0f,0.0f, 1.0f); 
	   glEnd(); 

}



///////////////////////////////////////////////////////////////////////////////
// Main entry point for GLUT based programs

int main(int argc, char* argv[]) {
  

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    glutInitWindowSize(1000, 800);
    glutCreateWindow("Triangle");
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);

    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }

    SetupRC();

    glutMainLoop();
    return 0;
}
